home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / kernel / dev / devTty.c < prev    next >
C/C++ Source or Header  |  1992-12-18  |  22KB  |  811 lines

  1. /* 
  2.  * devTty.c --
  3.  *
  4.  *    This file implements terminals and terminal-like devices for
  5.  *    Sprite.  It consists of a bunch of glue that hooks together a
  6.  *    generic terminal driver (the Td_ library), one or more
  7.  *    machine- and device-specific drivers for RS232 hardware,
  8.  *    and the generic Sprite kernel-call interfaces for devices.
  9.  *
  10.  * Copyright 1989 Regents of the University of California
  11.  * Permission to use, copy, modify, and distribute this
  12.  * software and its documentation for any purpose and without
  13.  * fee is hereby granted, provided that the above copyright
  14.  * notice appear in all copies.  The University of California
  15.  * makes no representations about the suitability of this
  16.  * software for any purpose.  It is provided "as is" without
  17.  * express or implied warranty.
  18.  */
  19.  
  20. #ifndef lint
  21. static char rcsid[] = "$Header: /cdrom/src/kernel/Cvsroot/kernel/dev/devTty.c,v 9.8 90/10/11 17:13:01 mendel Exp $ SPRITE (Berkeley)";
  22. #endif /* not lint */
  23.  
  24. #include <sprite.h>
  25. #include <stdio.h>
  26. #include <dev.h>
  27. #include <ttyAttach.h>
  28. #include <errno.h>
  29. #include <fs.h>
  30. #include <fsio.h>
  31. #include <proc.h>
  32. #include <status.h>
  33. #include <sync.h>
  34. #include <tty.h>
  35. #include <td.h>
  36. #include <compatInt.h>
  37. #include <fsioDevice.h>
  38. /*
  39.  * Monitor lock used for synchronizing access to DevTty and Td_Terminal
  40.  * structures.  See the comment above the declaration for DevTty structs
  41.  * (in devTty.h) for more information.  This lock may also be used by
  42.  * a few other files that interact closely with this one.
  43.  */
  44.  
  45. Sync_Lock devTtyLock = Sync_LockInitStatic("Dev:devTtyLock");
  46. #define LOCKPTR (&devTtyLock)
  47.  
  48. /*
  49.  * The following variable tells when the last user interaction occurred
  50.  * on the console.  It doesn't exactly belong here, but there isn't
  51.  * anyplace where it fits better.
  52.  */
  53.  
  54. Time        dev_LastConsoleInput;
  55.  
  56. /*
  57.  * Forward declarations for procedures defined in this file:
  58.  */
  59.  
  60. static int    CookedProc();
  61. static int    RawProc();
  62. static void    Signal();
  63. static void    Transfer();
  64. static void    TransferInProc();
  65. static void    TransferOutProc();
  66.  
  67. /*
  68.  *----------------------------------------------------------------------
  69.  *
  70.  * DevTtyOpen --
  71.  *
  72.  *    Called through devFsOpTable to open a terminal device.
  73.  *    Initializes the device and activates it so that it's ready
  74.  *    to return input.
  75.  *
  76.  * Results:
  77.  *    A standard Sprite ReturnStatus.
  78.  *
  79.  * Side effects:
  80.  *    The device will be "turned on" if it isn't already, which may
  81.  *    involve setting up interrupt handlers.
  82.  *
  83.  *----------------------------------------------------------------------
  84.  */
  85.  
  86. /* ARGSUSED */
  87. ENTRY ReturnStatus
  88. DevTtyOpen(devicePtr, useFlags, notifyToken, flagsPtr)
  89.     Fs_Device *devicePtr;    /* Information about device (e.g. type
  90.                  * and unit number). */
  91.     int useFlags;        /* Flags for the stream being opened:
  92.                  * OR'ed combination of FS_READ and
  93.                  * FS_WRITE. */
  94.     Fs_NotifyToken notifyToken;    /* Used for Fs call-back to notify waiting
  95.                  * processes that the terminal is ready. */
  96.     int *flagsPtr;            /* OUT: Device IO flags */             
  97. {
  98.     register DevTty *ttyPtr;
  99.     int result;
  100.  
  101.     LOCK_MONITOR;
  102.  
  103.     /*
  104.      * Call machine-specific code to attach to the device, then fill in
  105.      * all the fields that weren't already filled in by the attach procedure.
  106.      */
  107.  
  108.     ttyPtr = DevTtyAttach(devicePtr->unit);
  109.     if (ttyPtr == NULL) {
  110.     UNLOCK_MONITOR;
  111.     return Compat_MapToSprite(ENXIO);
  112.     }
  113.     if (ttyPtr->openCount == 0) {
  114.     ttyPtr->insertInput = 0;
  115.     ttyPtr->extractInput = 0;
  116.     ttyPtr->insertOutput = 0;
  117.     ttyPtr->extractOutput = 0;
  118.     ttyPtr->term = Td_Create(500, CookedProc, (ClientData) ttyPtr,
  119.         RawProc, (ClientData) ttyPtr);
  120.     ttyPtr->notifyToken = notifyToken;
  121.     ttyPtr->openCount = 0;
  122.     (*ttyPtr->activateProc)(ttyPtr->rawData);
  123.     } else if (ttyPtr->notifyToken != notifyToken) {
  124.     /*
  125.      * The console device is opened during boot time, at which
  126.      * time the proper notifyToken (i.e., a file system handle)
  127.      * is not available.  Here we reset the notifyToken to ensure
  128.      * proper communication between the device driver and the
  129.      * higher-level FS code.  See Fsio_BootTimeTtyOpen.
  130.      */
  131.     ttyPtr->notifyToken = notifyToken;
  132.     }
  133.  
  134.     /*
  135.      * Officially open the terminal.
  136.      */
  137.  
  138.     result = Td_Open(ttyPtr->term, &ttyPtr->selectState);
  139.     if (result != 0) {
  140.     if (ttyPtr->openCount == 0) {
  141.         Td_Delete(ttyPtr->term);
  142.     }
  143.     UNLOCK_MONITOR;
  144.     return Compat_MapToSprite(result);
  145.     }
  146.     ttyPtr->openCount++;
  147.     devicePtr->data = (ClientData) ttyPtr;
  148.     UNLOCK_MONITOR;
  149.     return SUCCESS;
  150. }
  151.  
  152. /*
  153.  *----------------------------------------------------------------------
  154.  *
  155.  * DevTtyRead --
  156.  *
  157.  *    Called through devFsOpTable to read from a terminal device.
  158.  *
  159.  * Results:
  160.  *    A standard Sprite ReturnStatus.  Characters are stored at
  161.  *    *readPtr->buffer, and the fields of *replyPtr are modified
  162.  *    to describe what happened.
  163.  *
  164.  * Side effects:
  165.  *    Information may be removed from the input buffer for the terminal.
  166.  *
  167.  *----------------------------------------------------------------------
  168.  */
  169.  
  170. /* ARGSUSED */
  171. ENTRY ReturnStatus
  172. DevTtyRead(devicePtr, readPtr, replyPtr)
  173.     Fs_Device *devicePtr;        /* Information about device. */
  174.     register Fs_IOParam *readPtr;    /* Input parameters. */
  175.     register Fs_IOReply *replyPtr;    /* Place to store return information. */
  176. {
  177.     register DevTty *ttyPtr = (DevTty *) devicePtr->data;
  178.     int result;
  179.  
  180.     LOCK_MONITOR;
  181.     replyPtr->length = readPtr->length;
  182.     result = Td_GetCooked(ttyPtr->term, readPtr->procID, readPtr->familyID,
  183.         &replyPtr->length, (char *) readPtr->buffer, &replyPtr->signal,
  184.         &ttyPtr->selectState);
  185.     replyPtr->flags = ttyPtr->selectState;
  186.     UNLOCK_MONITOR;
  187.     if (result != 0) {
  188.     return Compat_MapToSprite(result);
  189.     }
  190.     return SUCCESS;
  191. }
  192.  
  193. /*
  194.  *----------------------------------------------------------------------
  195.  *
  196.  * DevTtyWrite --
  197.  *
  198.  *    Called through devFsOpTable to write to a terminal device.
  199.  *
  200.  * Results:
  201.  *    A standard Sprite ReturnStatus.  Fields of *replyPtr are
  202.  *    modified to indicate what happened in the write operation.
  203.  *
  204.  * Side effects:
  205.  *    Information may be added to the output buffer for the terminal.
  206.  *
  207.  *----------------------------------------------------------------------
  208.  */
  209.  
  210. /* ARGSUSED */
  211. ENTRY ReturnStatus
  212. DevTtyWrite(devicePtr, writePtr, replyPtr)
  213.     Fs_Device *devicePtr;        /* Information about device. */
  214.     register Fs_IOParam *writePtr;    /* Input parameters. */
  215.     register Fs_IOReply *replyPtr;    /* Place to store result info. */
  216. {
  217.     register DevTty *ttyPtr = (DevTty *) devicePtr->data;
  218.     int result, countThisTime, stillToDo;
  219.     char *bufPtr;
  220.     ReturnStatus status = SUCCESS;
  221.  
  222.     LOCK_MONITOR;
  223.  
  224.     /*
  225.      * Td_PutCooked will accept anything we give it even if it exceeds
  226.      * the nominal buffer size.  To keep it from growing its output buffer
  227.      * very large, break big blocks up into small ones, and stop as soon
  228.      * as the FS_WRITABLE bit goes away (which means the nominal buffer
  229.      * size has been exceeded).
  230.      */
  231.  
  232.     replyPtr->length = 0;
  233.     stillToDo = writePtr->length;
  234.     bufPtr = (char *) writePtr->buffer;
  235.     while (stillToDo != 0) {
  236.     if (!(ttyPtr->selectState & FS_WRITABLE)) {
  237.         status = FS_WOULD_BLOCK;
  238.         break;
  239.     }
  240.     countThisTime = stillToDo;
  241.     if (countThisTime > 100) {
  242.         countThisTime = 100;
  243.     }
  244.     result = Td_PutCooked(ttyPtr->term, &countThisTime, bufPtr,
  245.         &replyPtr->signal, &ttyPtr->selectState);
  246.     replyPtr->flags = ttyPtr->selectState;
  247.     replyPtr->length += countThisTime;
  248.     bufPtr += countThisTime;
  249.     stillToDo -= countThisTime;
  250.     if (result != 0) {
  251.         status = Compat_MapToSprite(result);
  252.         break;
  253.     }
  254.     }
  255.     UNLOCK_MONITOR;
  256.     return status;
  257. }
  258.  
  259. /*
  260.  *----------------------------------------------------------------------
  261.  *
  262.  * DevTtyIOControl --
  263.  *
  264.  *    Called through devFsOpTable to perform IOControl operations on
  265.  *    a terminal device.
  266.  *
  267.  * Results:
  268.  *    A standard Sprite ReturnStatus.  *iocPtr->outBuffer may be
  269.  *    modified to hold the output information from the IOControl,
  270.  *    and the fields of *replyPtr are modified to show what happened.
  271.  *
  272.  * Side effects:
  273.  *    Depends on the IOControl operation.
  274.  *
  275.  *----------------------------------------------------------------------
  276.  */
  277.  
  278. /* ARGSUSED */
  279. ENTRY ReturnStatus
  280. DevTtyIOControl(devicePtr, iocPtr, replyPtr)
  281.     Fs_Device *devicePtr;        /* Information about device. */
  282.     register Fs_IOCParam *iocPtr;    /* Parameter information (buffer sizes
  283.                      * etc.). */
  284.     register Fs_IOReply *replyPtr;    /* Place to store result information. */
  285. {
  286.     register DevTty *ttyPtr = (DevTty *) devicePtr->data;
  287.     int result;
  288.  
  289.     LOCK_MONITOR;
  290.     replyPtr->length = iocPtr->outBufSize;
  291.     result = Td_ControlCooked(ttyPtr->term, iocPtr->command, iocPtr->format,
  292.         iocPtr->inBufSize, (char *) iocPtr->inBuffer,
  293.         &replyPtr->length, (char *) iocPtr->outBuffer,
  294.         &replyPtr->signal, &ttyPtr->selectState);
  295.     replyPtr->flags = ttyPtr->selectState;
  296.     UNLOCK_MONITOR;
  297.     if (result != 0) {
  298.     return Compat_MapToSprite(result);
  299.     }
  300.     return SUCCESS;
  301. }
  302.  
  303. /*
  304.  *----------------------------------------------------------------------
  305.  *
  306.  * DevTtySelect --
  307.  *
  308.  *    Called through devFsOpTable to perform select-related functions
  309.  *    on a terminal device.
  310.  *
  311.  * Results:
  312.  *    Always SUCCESS.  The values at *readPtr, *writePtr, and *exceptPtr
  313.  *    get set to zero if the device is NOT readable, or writable, or
  314.  *    exception-pending, respectively.
  315.  *
  316.  * Side effects:
  317.  *    None.
  318.  *
  319.  *----------------------------------------------------------------------
  320.  */
  321.  
  322. ReturnStatus
  323. DevTtySelect(devicePtr, readPtr, writePtr, exceptPtr)
  324.     Fs_Device *devicePtr;    /* Information about device. */
  325.     int *readPtr;        /* Set to zero if device not readable. */
  326.     int *writePtr;        /* Set to zero if device not writable. */
  327.     int *exceptPtr;        /* Set to zero if no exception pending on
  328.                  * device. */
  329. {
  330.     register DevTty *ttyPtr = (DevTty *) devicePtr->data;
  331.  
  332.     /*
  333.      * Because this is only a simple query, don't need any locking in
  334.      * this procedure.
  335.      */
  336.  
  337.     if (!(ttyPtr->selectState & FS_READABLE)) {
  338.     *readPtr = 0;
  339.     }
  340.     if (!(ttyPtr->selectState & FS_WRITABLE)) {
  341.     *writePtr = 0;
  342.     }
  343.     if (!(ttyPtr->selectState & FS_EXCEPTION)) {
  344.     *exceptPtr = 0;
  345.     }
  346.     return SUCCESS;
  347. }
  348.  
  349. /*
  350.  *----------------------------------------------------------------------
  351.  *
  352.  * DevTtyClose --
  353.  *
  354.  *    Called through devFsOpTable whenever a terminal is closed.
  355.  *
  356.  * Results:
  357.  *    A standard Sprite return status.
  358.  *
  359.  * Side effects:
  360.  *    Data structures get cleaned up and possibly deallocated.
  361.  *
  362.  *----------------------------------------------------------------------
  363.  */
  364.  
  365. /* ARGSUSED */
  366. ENTRY ReturnStatus
  367. DevTtyClose(devicePtr, useFlags, openCount, writerCount)
  368.     Fs_Device *devicePtr;        /* Information about device. */
  369.     int useFlags;            /* Indicates whether stream being
  370.                      * closed was open for reading and/or
  371.                      * writing:  OR'ed combination of
  372.                      * FS_READ and FS_WRITE. */
  373.     int openCount;            /* # of times this particular stream
  374.                      * is still open. */
  375.     int writerCount;            /* # of times this particular stream
  376.                      * is still open for writing. */
  377. {
  378.     DevTty *ttyPtr = (DevTty *) devicePtr->data;
  379.  
  380.     if (openCount > 0) {
  381.     return SUCCESS;
  382.     }
  383.  
  384.     LOCK_MONITOR;
  385.  
  386.     Td_Close(ttyPtr->term);
  387.     ttyPtr->openCount --;
  388.     if (ttyPtr->openCount == 0) {
  389.     Td_Delete(ttyPtr->term);
  390.     }
  391.     UNLOCK_MONITOR;
  392.     return SUCCESS;
  393. }
  394.  
  395. /*
  396.  *----------------------------------------------------------------------
  397.  *
  398.  * CookedProc --
  399.  *
  400.  *    This procedure is called by the Td library to perform control
  401.  *    operations on the "cooked" size of the terminal.
  402.  *
  403.  * Results:
  404.  *    Always zero, to indicate that no information is returned
  405.  *    in outBuffer.
  406.  *
  407.  * Side effects:
  408.  *    Depends on the control operation.  Most likely effect is to
  409.  *    wake up a waiting process.
  410.  *
  411.  *----------------------------------------------------------------------
  412.  */
  413.  
  414. /* ARGSUSED */
  415. INTERNAL static int
  416. CookedProc(ttyPtr, operation, inBufSize, inBuffer, outBufSize, outBuffer)
  417.     register DevTty *ttyPtr;    /* Our information about terminal. */
  418.     int operation;        /* What to do:  TD_COOKED_SIGNAL, etc. */
  419.     int inBufSize;        /* Size of input buffer for operation. */
  420.     char *inBuffer;        /* Input buffer. */
  421.     int outBufSize;        /* Size of output buffer for operation. */
  422.     char *outBuffer;        /* Output buffer. */
  423. {
  424.     int result = 0;
  425.     int sigNum, pID;
  426.  
  427.     switch (operation) {
  428.     case TD_COOKED_SIGNAL:
  429.         sigNum = ((int *) inBuffer)[0];
  430.         pID = ((int *) inBuffer)[1];
  431.         Signal(sigNum, (Proc_PID) pID, TRUE);
  432.         break;
  433.     case TD_COOKED_READS_OK:
  434.         if (!(ttyPtr->selectState & FS_READABLE)) {
  435.         ttyPtr->selectState |= FS_READABLE;
  436.         Fsio_DevNotifyReader(ttyPtr->notifyToken);
  437.         }
  438.         break;
  439.     case TD_COOKED_WRITES_OK:
  440.         if (!(ttyPtr->selectState & FS_WRITABLE)) {
  441.         ttyPtr->selectState |= FS_WRITABLE;
  442.         Fsio_DevNotifyWriter(ttyPtr->notifyToken);
  443.         }
  444.         break;
  445.     }
  446.     return result;
  447. }
  448.  
  449. /*
  450.  *----------------------------------------------------------------------
  451.  *
  452.  * RawProc --
  453.  *
  454.  *    This procedure is called by the Td library to perform control
  455.  *    operations on the "raw" size of the terminal.
  456.  *
  457.  * Results:
  458.  *    The return value is the number of bytes returned to the caller
  459.  *    at outBuffer.
  460.  *
  461.  * Side effects:
  462.  *    Depends on the control operation.  Most likely effect is to
  463.  *    start transferring output data.
  464.  *
  465.  *----------------------------------------------------------------------
  466.  */
  467.  
  468. /* ARGSUSED */
  469. INTERNAL static int
  470. RawProc(ttyPtr, operation, inBufSize, inBuffer, outBufSize, outBuffer)
  471.     register DevTty *ttyPtr;    /* Our information about terminal. */
  472.     int operation;        /* What to do:  TD_RAW_OUTPUT_READY etc. */
  473.     int inBufSize;        /* Size of input buffer for operation. */
  474.     char *inBuffer;        /* Input buffer. */
  475.     int outBufSize;        /* Size of output buffer for operation. */
  476.     char *outBuffer;        /* Output buffer. */
  477. {
  478.     /*
  479.      * Move data to the intermediate output buffer, if it's ready.
  480.      * Otherwise pass the operation on to the device-level procedure.
  481.      */
  482.  
  483.     if (operation == TD_RAW_OUTPUT_READY) {
  484.     Transfer(ttyPtr);
  485.     return 0;
  486.     }
  487.  
  488.     /*
  489.      * Don't actually close the device if it's the console:  otherwise
  490.      * we'd stop responding to console commands.
  491.      */
  492.  
  493.     if ((operation == TD_RAW_SHUTDOWN)
  494.         && (ttyPtr->consoleFlags & DEV_TTY_IS_CONSOLE)) {
  495.     return 0;
  496.     }
  497.  
  498.     return ttyPtr->rawProc(ttyPtr->rawData, operation, inBufSize, inBuffer,
  499.         outBufSize, outBuffer);
  500. }
  501.  
  502. /*
  503.  *----------------------------------------------------------------------
  504.  *
  505.  * DevTtyInputChar --
  506.  *
  507.  *    This procedure is invoked at interrupt level by device drivers
  508.  *    when an input character is received.
  509.  *
  510.  * Results:
  511.  *    None.
  512.  *
  513.  * Side effects:
  514.  *    The character is added to the buffer for ttyPtr, and arrangements
  515.  *    are made to process the character more fully in a process later.
  516.  *    If the buffer overflows, an error message is printed on the console.
  517.  *
  518.  *----------------------------------------------------------------------
  519.  */
  520.  
  521. void
  522. DevTtyInputChar(ttyPtr, value)
  523.     register DevTty *ttyPtr;    /* Our information about terminal. */
  524.     int value;            /* Character (or special condition like break)
  525.                  * that just arrived on terminal. */
  526. {
  527.     int next, old;
  528.  
  529.     old = ttyPtr->insertInput;
  530.     next = old+1;
  531.     if (next >= TTY_IN_BUF_SIZE) {
  532.     next = 0;
  533.     }
  534.     if (next == ttyPtr->extractInput) {
  535.     if (!(ttyPtr->consoleFlags & DEV_TTY_OVERFLOWED)) {
  536.         ttyPtr->consoleFlags |= DEV_TTY_OVERFLOWED;
  537.         printf("Buffer overflow in DevTtyInputChar\n");
  538.     } 
  539.     return;
  540.     }
  541.     ttyPtr->inBuffer[old] = value;
  542.  
  543.     /*
  544.      * Note: must advance insertInput before scheduling background
  545.      * procedure, in order to avoid race.
  546.      */
  547.  
  548.     ttyPtr->insertInput = next;
  549.     if (old == ttyPtr->extractInput) {
  550.     Proc_CallFunc(TransferInProc, (ClientData) ttyPtr, 0);
  551.     }
  552. }
  553.  
  554. /*
  555.  *----------------------------------------------------------------------
  556.  *
  557.  * TransferInProc --
  558.  *
  559.  *    This procedure is invoked in a kernel server process in response
  560.  *    to a Proc_CallFunc arrangement made by DevTtyInputChar. 
  561.  *
  562.  * Results:
  563.  *    None.
  564.  *
  565.  * Side effects:
  566.  *    Characters get removed from ttyPtr->inBuffer and sent off to the
  567.  *    Td library.
  568.  *
  569.  *----------------------------------------------------------------------
  570.  */
  571.  
  572. /* ARGSUSED */
  573. ENTRY static void
  574. TransferInProc(ttyPtr, callInfoPtr)
  575.     register DevTty *ttyPtr;        /* Our information about terminal. */
  576.     Proc_CallInfo *callInfoPtr;        /* Not used. */
  577. {
  578.     int value, next;
  579.     char c;
  580.  
  581.     LOCK_MONITOR;
  582.  
  583.     /*
  584.      * If the terminal is no longer open then don't do anything:  there's
  585.      * no Td_Terminal to do it on.
  586.      */
  587.  
  588.     if (ttyPtr->openCount == 0) {
  589.     UNLOCK_MONITOR;
  590.     return;
  591.     }
  592.  
  593.     while (ttyPtr->extractInput != ttyPtr->insertInput) {
  594.     value = ttyPtr->inBuffer[ttyPtr->extractInput];
  595.     next = ttyPtr->extractInput + 1;
  596.     if (next >= TTY_IN_BUF_SIZE) {
  597.         next = 0;
  598.     }
  599.     ttyPtr->extractInput = next;
  600.     if (ttyPtr->inputProc != (void (*)()) NIL) {
  601.         (*ttyPtr->inputProc)(ttyPtr->inputData, value);
  602.     } else {
  603.         if (value == DEV_TTY_BREAK) {
  604.         if (ttyPtr->consoleFlags & DEV_TTY_IS_CONSOLE) {
  605.             ttyPtr->consoleFlags |= DEV_TTY_GOT_BREAK;
  606.         } else {
  607.             Td_ControlRaw(ttyPtr->term, TD_BREAK);
  608.         }
  609.         } else {
  610.         if (value == DEV_TTY_HANGUP) {
  611.             Td_ControlRaw(ttyPtr->term, TD_LOST_CARRIER);
  612.         } else if ((ttyPtr->consoleFlags
  613.             & (DEV_TTY_GOT_BREAK|DEV_TTY_IS_CONSOLE))
  614.             == (DEV_TTY_GOT_BREAK|DEV_TTY_IS_CONSOLE)) {
  615.             Dev_InvokeConsoleCmd(value);
  616.         } else {
  617.             c = value;
  618.             Td_PutRaw(ttyPtr->term, 1, &c);
  619.         }
  620.         ttyPtr->consoleFlags &= ~DEV_TTY_GOT_BREAK;
  621.         }
  622.     }
  623.     if (ttyPtr->consoleFlags & DEV_TTY_IS_CONSOLE) {
  624.         Timer_GetTimeOfDay(&dev_LastConsoleInput, (int *) NIL,
  625.             (Boolean *) NIL);
  626.     }
  627.     }
  628.     ttyPtr->consoleFlags &= ~DEV_TTY_OVERFLOWED;
  629.  
  630.     UNLOCK_MONITOR;
  631. }
  632.  
  633. /*
  634.  *----------------------------------------------------------------------
  635.  *
  636.  * DevTtyOutputChar --
  637.  *
  638.  *    This procedure is called at interrupt level to retrieve the
  639.  *    next character ready for output, if there are any.
  640.  *
  641.  * Results:
  642.  *    The return value is either the next ASCII character ready
  643.  *    for output (returned unsigned in an int), or -1 to indicate
  644.  *    that the output buffer is empty.
  645.  *
  646.  * Side effects:
  647.  *    Characters are removed from ttyPtr's outBuffer, and a background-
  648.  *    level procedure call may be scheduled to refill the buffer.
  649.  *
  650.  *----------------------------------------------------------------------
  651.  */
  652.  
  653. int
  654. DevTtyOutputChar(ttyPtr)
  655.     register DevTty *ttyPtr;    /* Information about the terminal. */
  656. {
  657.     int result, next;
  658.  
  659.     if (ttyPtr->extractOutput == ttyPtr->insertOutput) {
  660.     return -1;
  661.     }
  662.     result = ttyPtr->outBuffer[ttyPtr->extractOutput];
  663.     next = ttyPtr->extractOutput + 1;
  664.     if (next >= TTY_OUT_BUF_SIZE) {
  665.     next = 0;
  666.     }
  667.     ttyPtr->extractOutput = next;
  668.     if (ttyPtr->extractOutput == ttyPtr->insertOutput) {
  669.     Proc_CallFunc(TransferOutProc, (ClientData) ttyPtr, 0);
  670.     }
  671.     return result;
  672. }
  673.  
  674. /*
  675.  *----------------------------------------------------------------------
  676.  *
  677.  * TransferOutProc --
  678.  *
  679.  *    This procedure is invoked in a kernel server process in response
  680.  *    to a Proc_CallFunc arrangement made by DevTtyOutputChar.
  681.  *
  682.  * Results:
  683.  *    None.
  684.  *
  685.  * Side effects:
  686.  *    Characters get transferred from Td's output buffer to the
  687.  *    intermediate buffer for Td.
  688.  *
  689.  *----------------------------------------------------------------------
  690.  */
  691.  
  692. /* ARGSUSED */
  693. ENTRY static void
  694. TransferOutProc(ttyPtr, callInfoPtr)
  695.     register DevTty *ttyPtr;        /* Our information about terminal. */
  696.     Proc_CallInfo *callInfoPtr;        /* Not used. */
  697. {
  698.     LOCK_MONITOR;
  699.  
  700.     /*
  701.      * Make sure that the terminal is still open.  Otherwise its Td_Terminal
  702.      * will have gone away.
  703.      */
  704.  
  705.     if (ttyPtr->openCount != 0) {
  706.     Transfer(ttyPtr);
  707.     }
  708.  
  709.     UNLOCK_MONITOR;
  710. }
  711.  
  712. /*
  713.  *----------------------------------------------------------------------
  714.  *
  715.  * Transfer --
  716.  *
  717.  *    Do all the real work of copying characters from the Td buffer
  718.  *    for a terminal to the intermediate buffer in ttyPtr.
  719.  *
  720.  * Results:
  721.  *    None.
  722.  *
  723.  * Side effects:
  724.  *    Characters get copied to the intermediate buffer.  If there's
  725.  *    really anything to copy, then the device-level rawProc gets
  726.  *    called to start up output.
  727.  *
  728.  *----------------------------------------------------------------------
  729.  */
  730.  
  731. INTERNAL static void
  732. Transfer(ttyPtr)
  733.     register DevTty *ttyPtr;    /* Information about terminal.  Caller must
  734.                  * have locked ttyPtr. */
  735. {
  736.     int count, next, tmp, oldDiff;
  737.  
  738.     /*
  739.      * Transfer characters in the largest possible blocks such that each
  740.      * block fits in the buffer without wrap-around.
  741.      */
  742.  
  743.     oldDiff = ttyPtr->insertOutput - ttyPtr->extractOutput;
  744.     while (TRUE) {
  745.     count = ttyPtr->extractOutput - ttyPtr->insertOutput - 1;
  746.     if (count < 0) {
  747.         count += TTY_OUT_BUF_SIZE;
  748.     }
  749.     if (count > (TTY_OUT_BUF_SIZE - ttyPtr->insertOutput)) {
  750.         count = TTY_OUT_BUF_SIZE - ttyPtr->insertOutput;
  751.     }
  752.     if (count <= 0) {
  753.         break;
  754.     }
  755.     tmp = Td_GetRaw(ttyPtr->term, count,
  756.         (char *) &ttyPtr->outBuffer[ttyPtr->insertOutput]);
  757.     next = ttyPtr->insertOutput + tmp;
  758.     if (next >= TTY_OUT_BUF_SIZE) {
  759.         next = 0;
  760.     }
  761.     ttyPtr->insertOutput = next;
  762.     if (tmp < count) {
  763.         break;
  764.     }
  765.     }
  766.  
  767.     /*
  768.      * Wake up the device if there didn't used to be characters in the
  769.      * buffer but there are now.
  770.      */
  771.  
  772.     if ((oldDiff == 0) && (ttyPtr->insertOutput != ttyPtr->extractOutput)) {
  773.     (*ttyPtr->rawProc)(ttyPtr->rawData, TD_RAW_OUTPUT_READY,
  774.         0, (char *) NIL, 0, (char *) NIL);
  775.     }
  776. }
  777.  
  778. /*
  779.  *----------------------------------------------------------------------
  780.  *
  781.  * Signal --
  782.  *
  783.  *    This is a utility procedure that converts a signal from UNIX to
  784.  *    Sprite and sends it to a process or group.
  785.  *
  786.  * Results:
  787.  *    None.
  788.  *
  789.  * Side effects:
  790.  *    A signal get sent.
  791.  *
  792.  *----------------------------------------------------------------------
  793.  */
  794.  
  795. static void
  796. Signal(sigNum, id, family)
  797.     int sigNum;                /* UNIX signal number to send. */
  798.     Proc_PID id;            /* Id of process or family. */
  799.     Boolean family;            /* TRUE means id is for family,
  800.                      * FALSE means it's for process. */
  801. {
  802.     int spriteSignal;
  803.  
  804.     if (Compat_UnixSignalToSprite(sigNum, &spriteSignal) != SUCCESS) {
  805.     printf("Warning: %s %d to Sprite.\n",
  806.         "devTty.Signal couldn't translate sigNum", sigNum);
  807.     } else {
  808.     (void) Sig_Send(spriteSignal, SIG_NO_CODE, id, family, (Address)0);
  809.     }
  810. }
  811.